package main

import (
	"fmt"
	"reflect"
)

/*
反射可以将“接口类型变量”转换为“反射类型对象”；
反射可以将“反射类型对象”转换为“接口类型变量”；
如果要修改“反射类型对象”，其值必须是“可写的”。
*/

// todo :第一 反射可以将“接口类型变量”转换为“反射类型对象”；
/*
反射类型如下：
const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Ptr
	Slice
	String
	Struct
	UnsafePointer
)

*/

func main01() {

	var x float64 = 3.4
	fmt.Println("type:", reflect.TypeOf(x))
	fmt.Println("value:", reflect.ValueOf(x))
	// interface ---->   Value
	//	Type 和 Value 都有一个名为 Kind 的方法，它会返回一个常量，表示底层数据的类型，常见值有：Uint、Float64、Slice 等。

	v := reflect.ValueOf(x)
	y := v.Interface().(float64) // y will have type float64.
	fmt.Println(y)

	reflect.ValueOf(x).Interface()
	// Value  -----> interface

}

// todo 第二 ： 反射可以将“反射类型对象”转换为“接口类型变量”

// todo 第三 ： 如果要修改“反射类型对象”其值必须是“可写的”
/*
	所谓可写，就是可寻址的，顾名思义，能拿到指针：
		那么传入数据是指针及UI可以了
		传入指针，拿到的Value 的 kind 是  ptr ,而不是传入参数的值类型
		Elem 可以解引用，获取真实的值和类型
		用CanSet 可以判断数据是否 settability
*/

func main() {
	var x float64 = 3.4
	fv := reflect.ValueOf(&x)

	fmt.Println(fv.Kind())        // ptr
	fmt.Println(fv.Elem().Kind()) // float64

	if fv.Elem().CanSet() {
		fv.Elem().SetFloat(6.28)
	}

	fmt.Println(x)
}
